package com.agent.demo;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class MyClassVisitor extends ClassVisitor {
    public MyClassVisitor(ClassVisitor classVisitor) {
        super(Opcodes.ASM9, classVisitor);
    }

    // 重写visitMethod对方法访问进行增强
    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

        MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
        return new MyMethodVisitor(mv, name);
    }


    static class MyMethodVisitor extends MethodVisitor implements Opcodes {

        private final String methodName;

        public MyMethodVisitor(MethodVisitor mv, String methodName) {
            super(Opcodes.ASM9, mv);
            this.methodName = methodName;
        }

        // visitCode方法是访问code的开始，重写后插入
        @Override
        public void visitCode() {
            super.visitCode();
            // 插入代码 TimeMonitor.start("xxx")，methodName就是xxx
            mv.visitLdcInsn(methodName); // 将一个常量加载到操作栈用
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/agent/demo/TimeMonitor",  "start", "(Ljava/lang/String;)V",false);
        }


        @Override
        public void visitInsn(int opcode) {
            // 正常方法退出、异常退出相关的指令，入栈前插入相应的代码，达到在方法尾部插入代码的目的
            if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
                    || opcode == Opcodes.ATHROW) {
                mv.visitLdcInsn(methodName);
                visitMethodInsn(Opcodes.INVOKESTATIC, "com/agent/demo/TimeMonitor",  "end", "(Ljava/lang/String;)V",false);
            }
            mv.visitInsn(opcode);
        }
    }


}
